import genetic
import random
import threading
from code import InteractiveConsole

import robot

class Gene():
	alleles = [True, False]
	
	def __init__(self,state=None):
		if state!= None:
			self.state=state
		else:
			self.state=self.randomChoice()
		
	def randomChoice(self):
		return random.choice(self.alleles)
	
	def mutate(self):
		self.state = not self.state #self.randomChoice()
	
	def value(self):
		return int(self.state)

	def __repr__(self):
		return str(int(self.state))
	
	def __eq__(self,other):
		if isinstance(other,Gene):
			return self.state==other.state
		else:
			return self.state==other
	
	def __ne__(self,other):
		return not self==other

class SortGene(Gene):
	def __init__(self,state=None,numSort=0):
		self.numSort=numSort
		self.state=state or self.randomChoice()
	
		SORT_MUTATION_RATE=0.8
	def randomChoice(self):
		choice=range(self.numSort)
		random.shuffle(choice)
		return choice
	
	
	def mutate(self):
		import copy
		current_state=copy.copy(self.state)
		new_state=[]
		
		if(self.numSort<2):
			return
		
		if (random.random()>0.98):
			numbers=random.sample(range(self.numSort),2)
			numbers.sort()
			
			new_state=[]
			new_state_randomed_area = self.state[numbers[0]:numbers[1]-self.numSort]
			random.shuffle(new_state_randomed_area)
			new_state=self.state[:numbers[0]] + new_state_randomed_area + self.state[numbers[1]-self.numSort:]
			
			self.state=new_state
		
		for i in range(self.numSort):
			if random.random()>0.93:
				new_i=random.randint(0,self.numSort-1)
				self.state[i],self.state[new_i] = self.state[new_i],self.state[i]
	def value(self):
		return int(self.state[0])
	
	def __repr__(self):
		return str([i+1 for i in self.state])

def str2Individual(ordString,areaString):
	#	:[4, 0, 16, 11, 9, 1, 13, 12, 3, 8, 6, 17, 14, 10, 5, 15, 2, 7]:111101111000111001001111011101101100100001111001111111110100100001100101
	#	orderstring	=	4, 0, 16, 11, 9, 1, 13, 12, 3, 8, 6, 17, 14, 10, 5, 15, 2, 7
	#	areaString	=	111101111000111001001111011101101100100001111001111111110100100001100101
	from geneticRoom import Gene,SortGene
	
	orderState= [int(item)-1 for item in ordString.split(', ')]
	orderGene = SortGene(state=orderState,numSort=len(orderState))
	
	areaGenes=[Gene(bool(int(bit))) for bit in areaString if bit.isdigit()]
	chromosome=[orderGene] + areaGenes
	
	return RoomIndividual(chromosome)

class RoomIndividual(genetic.Individual):
	optimization = genetic.MINIMIZE 
	def __init__(self, chromosome=None,numSort=None,everyone=0):
		if numSort==None and chromosome!=None:
			self.numSort=(len(chromosome)-1)/4
		else:
			self.numSort=numSort
		self.length=self.numSort*4+1
		
		self.chromosome = chromosome or self._makechromosome()
		self.score = None  # set during evaluation
		
		self.everyone=everyone
	
	def _makechromosome(self):
		sortGene=SortGene(numSort=self.numSort)
		areasGenes=[Gene() for gene in range(self.numSort*4)]
		return [sortGene]+areasGenes
	
	def crossover(self,other):
		#~ print "crossover",id(self),id(other)
		from random import random
		from copy import deepcopy
		chromosome=[]
		for i in range(self.length):
			if random()>0.5:
				chromosome.append(deepcopy(self.chromosome[i]))
			else:
				chromosome.append(deepcopy(other.chromosome[i]))
		
		ind= RoomIndividual(chromosome,self.numSort,everyone=self.everyone)
		
		#~ if (id(self)!=id(other)):
			#~ print "crossover",id(self),id(other),ind,id(ind)
		
		return ind
		
	
	def mutate(self, gene):
		print "entrou no mutate"
		self.chromosome[gene].mutate()
		
	def evaluate(self, optimum=None):
		self.score = sum([gene.value() for gene in self.chromosome])
	
	def __eq__(self,other):
		for i in range(len(self.chromosome)):
			if self.chromosome[i] != other.chromosome[i]:
				return False
		
		return True
	
	
class RoomCleaningMethod():
	def __init__(self,individual):
		self.time=individual.score
		
		orderGene = individual.chromosome[0]
		areaGenes = individual.chromosome[1-len(individual.chromosome):]
		
		self.orders = []
		
		for i in orderGene.state:
			self.orders.append((i,areaGenes[i*4+0],areaGenes[i*4+1],areaGenes[i*4+2],areaGenes[i*4+3]))
		
	def get_area(self,order):
		return order[0]
		
	def get_sOrder(self,order):
		return order[1]
	
	def get_clockWise(self,order):
		return self.get_xAxis(order)
		
	def get_xAxis(self,order):
		return order[2]
		
	def get_bot(self,order):
		return order[3]
		
	def get_left(self,order):
		return order[4]

def getPositionsFrom(room,individual):
	rcm=RoomCleaningMethod(individual)
	
	poss=[]
	
	for order in rcm.orders:
		#if rcm.get_sOrder(order) == True:
		area_num = rcm.get_area(order)
		area=room.areas[area_num]
		
		if rcm.get_sOrder(order)==1:
			orderPos=area.getPositionsOrdS(xAxis=(rcm.get_xAxis(order)==1),bot=(rcm.get_bot(order)==1),left=(rcm.get_left(order)==1))
		else:
			orderPos=area.getPositionsOrdCirc(clockWise=(rcm.get_clockWise(order)==1),bot=(rcm.get_bot(order)==1),left=(rcm.get_left(order)==1))
			
		if(len(poss)!=0):
			pathToArea=room.area.findPath(poss[len(poss)-1],orderPos[0])
			poss+=pathToArea
		poss+=orderPos
	return poss

class RoomSearchAreaCovering(threading.Thread):
	
	def __init__(self,room,population,generations,winner=None):
		threading.Thread.__init__(self)
		self.env = genetic.Environment(RoomIndividual, maxgenerations=generations, \
					optimum=0, numSort=len(room.areas),size=population,lastWinner=winner)
		self.room=room
		if winner:
			self.winner = winner
	
	def setRobot(self,robot):
		self.robot=robot
	
	
	def run(self):
		self.env.start()
		
		
		self.env.eventEvaluationWant.wait()
		while(self.env.individual2Evaluate is not None and self.env.individual2Evaluate is not 'end'):
			self.orderRobot(self.robot,self.env.individual2Evaluate)
			self.env.eventEvaluationWant.clear()
			self.env.eventEvaluationWant.wait()
		
		self.robot.isBeingControledBy=None
		del(self.room.robot)
		del(self.robot)
		#~ self.robot = None
		
		self.env.join()
		
		try:
			print "Terminou o AG do", self.room, "com melhoria de tempo de",self.winner.score-self.env.population[0].score,"s"
		except:
			print "Terminou o AG do", self.room, "com score de",self.env.population[0].score,"s"
		
		self.winner = self.env.population[0]
	
	def evaluate(self,score):
		individual = self.env.individual2Evaluate
		if isinstance(individual,RoomIndividual):
			individual.score=score
			#print individual
			self.env.eventEvaluationNeed.set()
	
	def bestPath(self):
		if self.winner is not None:
			poss=getPositionsFrom(self.room,individual)
			return poss
		else:
			return None
	
	def orderRobot(self,robot,individual):
		poss=getPositionsFrom(self.room,individual)
		#name='Limpeza do compartimento '+self.room.name+' Com genoma='+str(individual.chromosome)+'.' 
		name=None
		
		robot.pos=poss[0]
		robot.addOrder(name,poss)
		

class GeneticRobot(robot.Robot):
	
	def draw_update(self):
		pass
	
	def update(self):
		u"""Actualiza a cena para a pintar na imagem."""
		try:
			self.clock+=0.250
		except:
			self.clock=0.250
			
		self.move(0.040)
		if (not self.move_to_targets()):
			self.orderDone()
			self.executeNextOrder()
		
	
if __name__ == "__main__":
	sh = InteractiveConsole()
	print "\n"+47*"-"
	sh.push("import readline, rlcompleter")
	sh.push("readline.parse_and_bind('tab: complete')")
	sh.push("from geneticRoom import *")
	sh.push("c=GeneticRoom(5)")

	sh.push("c.start()")
	print 47*"-"
	
	sh.interact()
